﻿#region Using References

using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Input;
using Beaker.OpenCube.Dynamic;
using Beaker.OpenCube.Resources;
using Beaker.OpenCube.Textures;
using Beaker.OpenCube.WorldViewer.Messages;
using Beaker.Services.FileSystem;
using GalaSoft.MvvmLight.Command;

#endregion

namespace Beaker.OpenCube.WorldViewer.ViewModels
{
	public sealed class MainViewModel
		: ViewModel
	{
		private readonly DynamicGame _game;
		private DynamicWorld _currentWorld;

		public MainViewModel()
		{
			// create a game reader
			_game = new DynamicGame();

			// open default texture pack
			ITexturePack defaultTexturePack = _game.OpenDefaultTexturePack();
			//IResourcePack defaultResourcePack = _game.OpenDefaultResourcePack();

			// send message about the new texture pack
			new ChangeTexturePackMessage( defaultTexturePack )
				.Send();
			//new ChangeResourcePackMessage( defaultResourcePack )
			//	.Send();

			// create all viewmodels for the different views/modes
			_viewModels = new ReadOnlyCollection<ViewModel>(
				new ViewModel[]
				{
					new MapViewModel( this ),
					new ChunkViewModel( this ),
					new RenderViewModel( this )
				}
			);
			_activeView = _viewModels[0];

			// assign commands
			_setModeCommand = new RelayCommand<ViewMode>( SetMode );
		}

		public DynamicGame Game
		{
			get { return _game; }
		}

		#region View Mode

		private ViewMode _viewMode;
		private readonly RelayCommand<ViewMode> _setModeCommand;

		/// <summary>
		/// Gets or sets the view mode.
		/// </summary>
		/// <value>
		/// The view mode.
		/// </value>
		public ViewMode Mode
		{
			get { return _viewMode; }
			set { SetValue( ref _viewMode, value, OnViewModeChanged ); }
		}

		/// <summary>
		/// Called when the view mode changed.
		/// </summary>
		/// <param name="oldViewMode">The old view mode.</param>
		/// <param name="newViewMode">The new view mode.</param>
		private void OnViewModeChanged( ViewMode oldViewMode, ViewMode newViewMode )
		{
			// when view mode changes, these properties should also raise change notifications
			RaisePropertyChanged( () => IsInMapMode );
			RaisePropertyChanged( () => IsInChunkMode );
			RaisePropertyChanged( () => IsInRenderMode );

			ActiveView = _viewModels[(int)newViewMode];
		}

		/// <summary>
		/// Gets a value indicating whether the application is in map mode.
		/// </summary>
		/// <value>
		/// <c>true</c> if the application is in map mode; otherwise, <c>false</c>.
		/// </value>
		public bool IsInMapMode
		{
			get { return Mode == ViewMode.Map; }
		}

		/// <summary>
		/// Gets a value indicating whether the application is in chunk mode.
		/// </summary>
		/// <value>
		/// <c>true</c> if the application is in chunk mode; otherwise, <c>false</c>.
		/// </value>
		public bool IsInChunkMode
		{
			get { return Mode == ViewMode.Chunk; }
		}

		/// <summary>
		/// Gets a value indicating whether the application is in render mode.
		/// </summary>
		/// <value>
		/// <c>true</c> if the application is in render mode; otherwise, <c>false</c>.
		/// </value>
		public bool IsInRenderMode
		{
			get { return Mode == ViewMode.Render; }
		}

		/// <summary>
		/// Gets the command to set the mode.
		/// </summary>
		/// <value>
		/// The command to set the mode.
		/// </value>
		public ICommand SetModeCommand
		{
			get { return _setModeCommand; }
		}

		/// <summary>
		/// Sets the view mode.
		/// </summary>
		/// <param name="newMode">The new view mode.</param>
		private void SetMode( ViewMode newMode )
		{
			Mode = newMode;
		}

		#endregion
		#region ViewModels

		private readonly IList<ViewModel> _viewModels;
		private ViewModel _activeView;

		/// <summary>
		/// Gets or sets the active view model to display
		/// </summary>
		public ViewModel ActiveView
		{
			get { return _activeView; }
			set { SetValue( ref _activeView, value ); }
		}

		#endregion

		public IEnumerable<OpenProfileViewModel> Profiles
		{
			get
			{
				return
					from profile in _game.GetProfiles().Profiles.Values
					select new OpenProfileViewModel( this, profile );
			}
		}


		/// <summary>
		/// Get a sequence of all the worlds by names.
		/// </summary>
		/// <value>
		/// Sequence of all the worlds by their names.
		/// </value>
		public IEnumerable<OpenWorldViewModel> Worlds
		{
			get
			{
				return
					from folder in _game.GetWorldFolders()
					select new OpenWorldViewModel( this, folder );
			}
		}

		/// <summary>
		/// Opens the world in the given folder.
		/// </summary>
		/// <param name="worldFolder">Folder of the world to open.</param>
		public void OpenWorld( IFolder worldFolder )
		{
			CurrentWorld = _game.OpenWorld( worldFolder );
		}

		/// <summary>
		/// Gets or sets the current world.
		/// </summary>
		/// <value>
		/// The current world.
		/// </value>
		public DynamicWorld CurrentWorld
		{
			get { return _currentWorld; }
			private set { SetValue( ref _currentWorld, value, OnCurrentWorldChanged ); }
		}

		private void OnCurrentWorldChanged( DynamicWorld oldWorld, DynamicWorld newWorld )
		{
			RaisePropertyChanged( () => WorldName );
		}

		/// <summary>
		/// Gets the name of the world.
		/// </summary>
		/// <value>
		/// The name of the world.
		/// </value>
		public string WorldName
		{
			get
			{
				if( _currentWorld == null )
					return string.Empty;

				return _currentWorld.LevelData.LevelName;
			}
		}

		public IEnumerable<OpenTexturePackViewModel> TexturePacks
		{
			get
			{
				return
					from name in _game.GetTexturePackFiles()
					select new OpenTexturePackViewModel( this, name );
			}
		}
	}
}
